package jobs;

import java.util.List;
import java.util.Map;

import models.FileRevision;
import models.Repository;
import models.RepositoryFile;
import models.Revision;
import models.FileRevision.ChangeAction;

import org.tmatesoft.svn.core.SVNLogEntry;
import org.tmatesoft.svn.core.SVNLogEntryPath;

import play.Logger;
import play.jobs.Job;
import play.jobs.On;
import svnservice.SVNServiceImpl;

@On("*/5 * * * * ?")
public class SVNPoller extends Job {
	
	private SVNService svnService;

	@Override
	public void doJob() throws Exception {
		if (svnService == null) {
			svnService = new SVNServiceImpl();
		}
		final List<Repository> findAll = Repository.findAllEnabled();
		Logger.info("There are "+findAll.size()+" repositories to check");
		for (final Repository repositoryToCheck : findAll) {
			Logger.info("Checking repository "+repositoryToCheck.id);
			svnService.connectToRepository(repositoryToCheck);
			try {
				final long latestRevisionForRepository = svnService.getLatestRevisionForRepository(repositoryToCheck);
				Logger.info("Last revision for this repository is " + latestRevisionForRepository);
				if (repositoryToCheck.lastRevisionInRepository != latestRevisionForRepository) {
					repositoryToCheck.lastRevisionInRepository = latestRevisionForRepository;
					repositoryToCheck.save();
				}
				Logger.info("Last stored revision is "+repositoryToCheck.lastRevision);
				int count = 0;
				final int maximum = 100;
				while (count < maximum && repositoryToCheck.lastRevision < latestRevisionForRepository) {
					final long i = repositoryToCheck.lastRevision+1;
				//for (long i = repositoryToCheck.lastRevision+1 ; i <= latestRevisionForRepository; i++) {
					final SVNLogEntry logEntry = svnService.getLogEntryForEntry(i);
					Logger.info("Procssing revision "+logEntry.getRevision());
					final Revision r = new Revision();
					r.revisionDate = logEntry.getDate();
					r.revisionUser = logEntry.getAuthor();
					final String message = logEntry.getMessage().replace('?', ' ').replace(';', ' ');
					if (message.length()>255) {
						r.revisionMessage = message.substring(0, 255);
					} else {
						r.revisionMessage = message;
					}
					r.revision = logEntry.getRevision();
					repositoryToCheck.revisions.add(r);
					@SuppressWarnings("unchecked")
					final Map<String, SVNLogEntryPath> changedPaths = logEntry.getChangedPaths();
					Logger.info("Processing "+changedPaths.size()+ " changed paths");
					for (final Map.Entry<String, SVNLogEntryPath> path : changedPaths.entrySet()) {
						Logger.info("Processing "+path.getKey());
						final RepositoryFile repositoryFile = RepositoryFile.findOrCreateByPath(repositoryToCheck, path.getKey());
						final SVNLogEntryPath pathEntry = path.getValue();
						final char type = pathEntry.getType();
						final FileRevision fileRevision = new FileRevision();
						switch (type) {
						case SVNLogEntryPath.TYPE_ADDED:
							fileRevision.changeAction = ChangeAction.ADD;
							break;
						case SVNLogEntryPath.TYPE_DELETED:
							fileRevision.changeAction = ChangeAction.DELETE;
							break;
						case SVNLogEntryPath.TYPE_MODIFIED:
						case SVNLogEntryPath.TYPE_REPLACED:
							fileRevision.changeAction = ChangeAction.MODIFY;
							break;
						default:
							throw new IllegalStateException("Unrecognised change type:"+type);
						}
						fileRevision.repositoryFile = repositoryFile;
						fileRevision.revision = r;
						r.save();
						repositoryFile.merge();
						fileRevision.save();
					}
					r.save();
					repositoryToCheck.lastRevision=i;
					repositoryToCheck.save();
					++count;
				}
			Logger.info("Updated "+count+" revisions");
			} finally {
				svnService.disconnect();
			}
		}
	}
	
}
